from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
import json
import os
import sys
import base64
import re
import shutil
import sqlite3
from datetime import datetime
from werkzeug.utils import secure_filename
from database import HotspotDatabase

# 设置控制台编码为UTF-8
if sys.platform.startswith('win'):
    import codecs
    sys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach())
    sys.stderr = codecs.getwriter('utf-8')(sys.stderr.detach())

app = Flask(__name__, static_folder='.', static_url_path='')
CORS(app)  # 允许跨域请求

# 配置
DATA_FILE = 'map_hotspots_data.json'  # 保留用于备份
DB_FILE = 'map_hotspots.db'
BACKUP_FILE = 'map_hotspots_data_backup.json'
IMG_FOLDER = 'IMG'
MAX_IMAGE_SIZE = 10 * 1024 * 1024  # 10MB
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg'}

# 初始化数据库
db = HotspotDatabase(DB_FILE)

# 确保文件夹存在
if not os.path.exists(IMG_FOLDER):
    os.makedirs(IMG_FOLDER)

# 创建备份文件夹
BACKUP_FOLDER = 'backups'
if not os.path.exists(BACKUP_FOLDER):
    os.makedirs(BACKUP_FOLDER)

def allowed_file(filename):
    """检查文件扩展名是否允许"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def sanitize_filename(filename):
    """清理文件名，移除特殊字符"""
    # 移除或替换不安全的字符
    filename = re.sub(r'[<>:"/\\|?*]', '_', filename)
    # 限制长度
    if len(filename) > 100:
        name, ext = os.path.splitext(filename)
        filename = name[:100-len(ext)] + ext
    return filename

def create_backup():
    """创建数据备份"""
    try:
        # 从数据库导出数据
        data = db.export_to_json_format()
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        backup_path = os.path.join(BACKUP_FOLDER, f'backup_{timestamp}.json')
        
        with open(backup_path, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        
        print(f"备份已创建: {backup_path}")
        return True
    except Exception as e:
        print(f"创建备份失败: {e}")
        return False

@app.route('/')
def index():
    return send_from_directory('.', '地图.html')

@app.route('/IMG/<path:filename>')
def serve_image(filename):
    return send_from_directory('IMG', filename)

@app.route('/upload-image', methods=['POST'])
def upload_image():
    try:
        data = request.json
        image_data = data.get('imageData')  # base64编码的图片数据
        filename = data.get('filename')     # 文件名
        
        if not image_data or not filename:
            return jsonify({"success": False, "message": "缺少图片数据或文件名"}), 400
        
        # 验证文件扩展名
        if not allowed_file(filename):
            return jsonify({"success": False, "message": f"不支持的文件格式。支持的格式: {', '.join(ALLOWED_EXTENSIONS)}"}), 400
        
        # 移除base64前缀
        if ',' in image_data:
            image_data = image_data.split(',')[1]
        
        # 解码base64数据
        try:
            image_bytes = base64.b64decode(image_data)
        except Exception as e:
            return jsonify({"success": False, "message": "图片数据格式错误"}), 400
        
        # 检查文件大小
        if len(image_bytes) > MAX_IMAGE_SIZE:
            return jsonify({"success": False, "message": f"图片文件过大。最大支持 {MAX_IMAGE_SIZE // (1024*1024)}MB"}), 400
        
        # 清理文件名
        safe_filename = sanitize_filename(os.path.basename(filename))
        file_path = os.path.join(IMG_FOLDER, safe_filename)
        
        # 检查文件是否已存在，如果存在则重命名
        counter = 1
        original_path = file_path
        while os.path.exists(file_path):
            name, ext = os.path.splitext(original_path)
            file_path = f"{name}_{counter}{ext}"
            counter += 1
            if counter > 100:  # 防止无限循环
                return jsonify({"success": False, "message": "文件名冲突，请重命名文件"}), 400
        
        # 保存图片文件
        with open(file_path, 'wb') as f:
            f.write(image_bytes)
        
        print(f"图片已保存到: {file_path}")
        return jsonify({
            "success": True, 
            "message": "图片上传成功",
            "filename": os.path.basename(file_path),
            "path": f"IMG/{os.path.basename(file_path)}"
        })
        
    except Exception as e:
        print(f"图片上传失败: {e}")
        return jsonify({"success": False, "message": f"图片上传失败: {str(e)}"}), 500

@app.route('/save-data', methods=['POST'])
def save_data():
    try:
        data = request.json
        
        # 验证数据格式
        if not isinstance(data, dict):
            return jsonify({"success": False, "message": "数据格式错误"}), 400
        
        # 创建备份
        create_backup()
        
        # 保存到数据库
        save_result = save_data_to_db(data)
        if save_result:
            print("数据已保存到数据库")
            return jsonify({"success": True, "message": "数据保存成功"})
        else:
            return jsonify({"success": False, "message": "数据保存失败"}), 500
    
    except Exception as e:
        print(f"保存数据失败: {e}")
        return jsonify({"success": False, "message": f"保存失败: {str(e)}"}), 500

def save_data_to_db(data):
    """将数据保存到数据库"""
    try:
        # 清除现有数据（为了简化，这里重新创建）
        # 在生产环境中应该做增量更新
        import sqlite3
        with sqlite3.connect(DB_FILE) as conn:
            cursor = conn.cursor()
            # 清空表（保留结构）
            cursor.execute('DELETE FROM hotspot_info')
            cursor.execute('DELETE FROM hotspots')
            cursor.execute('DELETE FROM images')
            
        # 保存图片数据
        images = data.get('imageData', {}).get('images', [])
        image_id_mapping = {}
        
        for image in images:
            original_id = image['id']
            new_id = db.add_image(
                src=image['src'],
                width=image.get('width'),
                height=image.get('height')
            )
            image_id_mapping[original_id] = new_id
            
            # 保存热点
            for hotspot in image.get('hotspots', []):
                db.add_hotspot(
                    image_id=new_id,
                    href=hotspot['href'],
                    coords=hotspot['coords'],
                    hotspot_id=hotspot['id']
                )
        
        # 保存热点信息
        hotspot_info = data.get('hotspotInfo', {})
        for href, content in hotspot_info.items():
            db.add_hotspot_info(href, content)
        
        # 保存下一个热点ID
        next_hotspot_id = data.get('nextHotspotId', 1)
        db.set_config('next_hotspot_id', str(next_hotspot_id))
        
        return True
    except Exception as e:
        print(f"保存数据到数据库失败: {e}")
        return False

@app.route('/load-data', methods=['GET'])
def load_data():
    try:
        # 从数据库加载数据
        data = db.export_to_json_format()
        return jsonify({"success": True, "data": data})
    
    except Exception as e:
        print(f"加载数据失败: {e}")
        return jsonify({"success": False, "message": f"加载失败: {str(e)}"}), 500

@app.route('/save_hotspot_info', methods=['POST'])
def save_hotspot_info():
    """保存单个热点的信息"""
    try:
        data = request.json
        href = data.get('href')
        info = data.get('info', '')
        
        if not href:
            return jsonify({"success": False, "error": "缺少href参数"}), 400
        
        # 更新数据库中的热点信息
        result = db.update_hotspot_info(href, info)
        
        if result:
            print(f"热点信息已更新: {href}")
            return jsonify({"success": True, "message": "热点信息保存成功"})
        else:
            return jsonify({"success": False, "error": "保存到数据库失败"}), 500
            
    except Exception as e:
        print(f"保存热点信息失败: {e}")
        return jsonify({"success": False, "error": f"保存失败: {str(e)}"}), 500

@app.route('/save_hotspot_name', methods=['POST'])
def save_hotspot_name():
    """保存热点自定义名称"""
    try:
        data = request.json
        hotspot_id = data.get('hotspot_id')
        name = data.get('name', '')
        
        if not hotspot_id:
            return jsonify({"success": False, "error": "缺少hotspot_id参数"}), 400
        
        # 更新数据库中的热点名称
        result = db.update_hotspot_name(hotspot_id, name)
        
        if result:
            print(f"热点名称已更新: {hotspot_id} -> {name}")
            return jsonify({"success": True, "message": "热点名称保存成功"})
        else:
            return jsonify({"success": False, "error": "保存到数据库失败"}), 500
            
    except Exception as e:
        print(f"保存热点名称失败: {e}")
        return jsonify({"success": False, "error": f"保存失败: {str(e)}"}), 500

@app.route('/server-status', methods=['GET'])
def server_status():
    """检查服务器状态"""
    try:
        return jsonify({
            "success": True,
            "status": "running",
            "timestamp": datetime.now().isoformat(),
            "dataFile": os.path.exists(DATA_FILE),
            "imgFolder": os.path.exists(IMG_FOLDER)
        })
    except Exception as e:
        return jsonify({"success": False, "status": "error", "message": str(e)}), 500

@app.route('/list-backups', methods=['GET'])
def list_backups():
    """列出所有备份文件"""
    try:
        backups = []
        if os.path.exists(BACKUP_FOLDER):
            for file in os.listdir(BACKUP_FOLDER):
                if file.endswith('.json'):
                    file_path = os.path.join(BACKUP_FOLDER, file)
                    stat = os.stat(file_path)
                    backups.append({
                        "filename": file,
                        "size": stat.st_size,
                        "modified": datetime.fromtimestamp(stat.st_mtime).isoformat()
                    })
        
        backups.sort(key=lambda x: x['modified'], reverse=True)
        return jsonify({"success": True, "backups": backups})
    except Exception as e:
        return jsonify({"success": False, "message": str(e)}), 500

@app.route('/delete-image/<int:image_id>', methods=['DELETE'])
def delete_image(image_id):
    """删除图片及其相关热点"""
    try:
        # 从数据库获取图片信息
        images = db.get_all_images()
        image_to_delete = None
        
        for img in images:
            if img.get('id') == image_id:
                image_to_delete = img
                break
        
        if not image_to_delete:
            return jsonify({"success": False, "message": f"图片ID {image_id} 不存在"}), 404
        
        # 获取图片文件名
        image_src = image_to_delete.get('src', '')
        if image_src.startswith('IMG/'):
            image_filename = image_src[4:]  # 移除 'IMG/' 前缀
            image_path = os.path.join(IMG_FOLDER, image_filename)
            
            # 删除图片文件
            if os.path.exists(image_path):
                os.remove(image_path)
                print(f"图片文件已删除: {image_path}")
        
        # 删除图片数据
        deleted_hotspots = image_to_delete.get('hotspots', [])
        
        # 创建备份
        create_backup()
        
        # 从数据库删除图片及其相关热点
        success = db.delete_image(image_id)
        if not success:
            return jsonify({"success": False, "message": "删除图片失败"}), 500
        
        print(f"图片 {image_id} 及其 {len(deleted_hotspots)} 个热点已删除")
        return jsonify({
            "success": True, 
            "message": f"图片 {image_id} 删除成功",
            "deletedHotspots": len(deleted_hotspots)
        })
        
    except Exception as e:
        print(f"删除图片失败: {e}")
        return jsonify({"success": False, "message": f"删除失败: {str(e)}"}), 500

@app.route('/delete-hotspot/<path:href>', methods=['DELETE'])
def delete_hotspot(href):
    """删除指定热点"""
    try:
        print(f"🗑️ 收到删除热点请求: {href}")
        sys.stdout.flush()  # 强制刷新输出
        
        # 检查热点是否存在于hotspot_info表
        hotspot_info = db.get_all_hotspot_info()
        print(f"📊 数据库中的热点信息: {list(hotspot_info.keys())}")
        sys.stdout.flush()  # 强制刷新输出
        
        # 也检查hotspots表
        with sqlite3.connect(DB_FILE) as conn:
            cursor = conn.cursor()
            cursor.execute('SELECT href FROM hotspots WHERE href = ?', (href,))
            hotspot_exists = cursor.fetchone() is not None
            print(f"🔍 热点 {href} 在hotspots表中存在: {hotspot_exists}")
        
        # 如果热点在任一表中不存在，仍然返回成功（前端已经删除了）
        if href not in hotspot_info and not hotspot_exists:
            print(f"⚠️ 热点 {href} 在数据库中不存在，但前端已删除，返回成功")
            return jsonify({"success": True, "message": f"热点 {href} 删除成功（前端已删除）"})
        
        # 创建备份
        create_backup()
        
        # 从数据库删除热点
        success = db.delete_hotspot(href)
        print(f"🔧 数据库删除操作结果: {success}")
        
        if not success:
            print(f"⚠️ 数据库删除操作返回失败，但可能是因为热点已不存在")
            # 如果删除失败，但前端已经删除了，仍然返回成功
            return jsonify({"success": True, "message": f"热点 {href} 删除完成"})
        
        print(f"✅ 热点 {href} 已成功从数据库删除")
        return jsonify({"success": True, "message": f"热点 {href} 删除成功"})
        
    except Exception as e:
        print(f"❌ 删除热点失败: {e}")
        import traceback
        print(f"🐛 错误堆栈: {traceback.format_exc()}")
        return jsonify({"success": False, "message": f"删除失败: {str(e)}"}), 500

@app.route('/update-hotspot-coords', methods=['POST'])
def update_hotspot_coords():
    """更新热点坐标"""
    try:
        data = request.json
        href = data.get('href')
        coords = data.get('coords')
        
        if not href or not coords:
            return jsonify({"success": False, "message": "缺少热点href或坐标信息"}), 400
        
        # 更新数据库中的热点坐标
        success = db.update_hotspot_coords(href, coords)
        if not success:
            return jsonify({"success": False, "message": f"热点 {href} 未找到"}), 404
        
        print(f"更新热点 {href} 坐标: {coords}")
        
        return jsonify({"success": True, "message": f"热点 {href} 坐标更新成功"})
        
    except Exception as e:
        print(f"更新热点坐标失败: {e}")
        return jsonify({"success": False, "message": f"更新失败: {str(e)}"}), 500

@app.route('/sync-data', methods=['POST'])
def sync_data():
    """同步数据到服务器"""
    try:
        data = request.json
        
        # 验证数据格式
        if not isinstance(data, dict):
            return jsonify({"success": False, "message": "数据格式错误"}), 400
        
        # 添加保存时间戳
        data['lastUpdated'] = datetime.now().isoformat()
        
        # 创建备份
        create_backup()
        
        # 保存到JSON文件
        with open(DATA_FILE, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        
        print(f"数据已同步到 {DATA_FILE}")
        return jsonify({
            "success": True, 
            "message": "数据同步成功",
            "timestamp": data['lastUpdated']
        })
        
    except Exception as e:
        print(f"数据同步失败: {e}")
        return jsonify({"success": False, "message": f"同步失败: {str(e)}"}), 500



@app.route('/get-data-info', methods=['GET'])
def get_data_info():
    """获取数据文件信息"""
    try:
        if not os.path.exists(DATA_FILE):
            return jsonify({
                "success": False, 
                "message": "数据文件不存在",
                "exists": False
            })
        
        # 获取文件信息
        stat = os.stat(DATA_FILE)
        
        # 读取数据基本信息
        with open(DATA_FILE, 'r', encoding='utf-8') as f:
            data = json.load(f)
        
        image_count = len(data.get('imageData', {}).get('images', []))
        hotspot_count = len(data.get('hotspotInfo', {}))
        last_updated = data.get('lastUpdated', '未知')
        
        return jsonify({
            "success": True,
            "exists": True,
            "fileSize": stat.st_size,
            "lastModified": datetime.fromtimestamp(stat.st_mtime).isoformat(),
            "imageCount": image_count,
            "hotspotCount": hotspot_count,
            "lastUpdated": last_updated
        })
        
    except Exception as e:
        print(f"获取数据信息失败: {e}")
        return jsonify({"success": False, "message": f"获取信息失败: {str(e)}"}), 500

@app.route('/restore-backup/<filename>', methods=['POST'])
def restore_backup(filename):
    """恢复备份文件"""
    try:
        backup_path = os.path.join(BACKUP_FOLDER, filename)
        if not os.path.exists(backup_path):
            return jsonify({"success": False, "message": "备份文件不存在"}), 404
        
        # 创建当前数据的备份
        create_backup()
        
        # 恢复备份
        shutil.copy2(backup_path, DATA_FILE)
        
        return jsonify({"success": True, "message": "备份恢复成功"})
    except Exception as e:
        return jsonify({"success": False, "message": str(e)}), 500

if __name__ == '__main__':
    print("=" * 50)
    print("    地图热点展示服务器")
    print("=" * 50)
    print(f"访问地址: http://localhost:8000")
    print(f"数据文件: {DATA_FILE}")
    print("=" * 50)
    print("服务器启动中...")
    app.run(host='0.0.0.0', port=8000, debug=True)
